/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Multi-Service Worker Class
 *		Provides a threaded mechanism for performing service-related operations for
 * multiple service instances.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Threading;
using System.ServiceProcess;
using System.Windows.Forms;

namespace Adaptive.Foundation.SysTools
{
    /// <summary>
    /// Provides a threaded mechanism for performing service-related operations for 
    /// multiple service instances.
    /// </summary>
    /// <remarks>
    /// This class provides independently-threaded service operations for one or more
    /// service instances.
    /// </remarks>
    public sealed class MultiServiceWorker : SingleServiceWorker
    {
        /*--------------------------------------------------------------------------------
         * Public Events
         *------------------------------------------------------------------------------*/
        #region Public Events
        /// <summary>
        /// Occurs to update the UI as to the current status.
        /// </summary>
        public event ProgressEventHandler ProgressUpdate;
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations
        /// <summary>
        /// List of services to operate upon.
        /// </summary>
        private ServiceControllerExCollection _itemList;
        /// <summary>
        /// Internal execution manager thread.
        /// </summary>
        private Thread _executionThread;
        /// <summary>
        /// Cancel flag.
        /// </summary>
        private bool _cancelOp;
        /// <summary>
        /// Desired service status.
        /// </summary>
        private ServiceControllerStatus _desiredStatus = ServiceControllerStatus.Running;
        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <value>
        /// This is the default constructor.
        /// </value>
        /// <param name="serviceList">
        /// An array of  <see cref="ServiceControllerEx"/> instances to be operated on.
        /// </param>
        public MultiServiceWorker(ServiceControllerEx[] serviceList) : base(null)
        {
            _itemList = new ServiceControllerExCollection();
            foreach (ServiceControllerEx item in serviceList)
                _itemList.Add(item);
        }
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <param name="serviceList">
        /// A <see cref="ServiceControllerExCollection"/> instance containing the 
        /// service instances to be operated on.
        /// </param>
        public MultiServiceWorker(ServiceControllerExCollection serviceList)
            : base(null)
        {
            _itemList = new ServiceControllerExCollection();
            serviceList.MoveFirst();
            while (!serviceList.Eof)
            {
                _itemList.Add(serviceList.Value);
                serviceList.MoveNext();
            }
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            if ((!Disposed) && (disposing))
            {
                if (_itemList != null)
                    _itemList.Dispose();
            }
            _executionThread = null;
            _itemList = null;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets a value indicating whether the object is executing an operation.
        /// </summary>
        /// <value>
        /// <b>true</b> if an operation is currently in progress; otherwise,
        /// <b>false</b>.
        /// </value>
        public new bool Executing
        {
            get { return ((_executionThread != null) && (_executionThread.IsAlive)); }
        }
        /// <summary>
        /// Gets or sets  a value indicating whether the current thread is to be 
        /// cancelled.
        /// </summary>
        /// <value>
        /// <b>true</b> to cancel the current operation; otherwise, <b>false</b>.
        /// </value>
        public bool Cancel
        {
            get { return _cancelOp; }
            set { _cancelOp = value; }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Protected Methods
         *------------------------------------------------------------------------------*/
        #region Protected Methods
        /// <summary>
        /// Creates the internal thread mechanism and launches the operation manager thread.
        /// </summary>
        /// <param name="status">
        /// A <see cref="ServiceControllerStatus"/> enumerated value indicating 
        /// the desired status for the internal services to be set to.
        /// </param>
        protected override void InitializeThread(ServiceControllerStatus status)
        {
            _cancelOp = false;
            _executionThread = new Thread(new ParameterizedThreadStart(ExecuteManagerThread));
            _executionThread.IsBackground = true;
            _executionThread.Priority = ThreadPriority.Normal;
            _desiredStatus = status;
        }
        /// <summary>
        /// Executes the thread that Sets the state for the internal service list.
        /// </summary>
        private void ExecuteManagerThread(object status)
        {
            ProgressEventArgs evArgs = null;    //UI status update event arguments.
            int length = 0;                     //Iteration limit.
            int count = 0;                      //Iteration counter.

            evArgs = new ProgressEventArgs();
            length = _itemList.Count;
            do
            {
                //Update the UI.
                evArgs.Status = _itemList[count].DisplayName;
                evArgs.PercentComplete = (int)(((float)count / length) * 100);
                OnProgressUpdate(evArgs);

                //Allow the base class to set the service object and raise any neccessary events.
                BaseSetService(_itemList[count]);
                base.BeginServiceOperation(_desiredStatus);
                base.EndServiceOperation();

                count++;
                //Go to end or cancelled.
            } while ((count < length) && (!_cancelOp));

            //Update the UI.
            evArgs.Status = "Complete.";
            evArgs.PercentComplete = 100;
            OnProgressUpdate(evArgs);
        }
        /// <summary>
        /// Raises the <see cref="ProgressUpdate"/> event.
        /// </summary>
        /// <param name="e">
        /// An <see cref="ProgressEventArgs"/> event arguments instance containing
        /// current status data.
        /// </param>
        private void OnProgressUpdate(ProgressEventArgs e)
        {
            if (ProgressUpdate != null)
                ProgressUpdate(this, e);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Begins the asynchronous service start process.
        /// </summary>
        public override void BeginServiceOperation(ServiceControllerStatus status)
        {
            // Initialize the internal worker thread.
            InitializeThread(status);

            //Begin.
            _executionThread.Start();
        }
        /// <summary>
        /// Waits for the current operation to terminate.
        /// </summary>
        public override void EndServiceOperation()
        {
            //Wait for the internal thread to stop.
            while ((_executionThread != null) && (_executionThread.IsAlive))
            {
                //Wait.
                Thread.Sleep(100);

                //Allow UI to update - required for UI's Invoke() mechanism to work properly with
                //threaded events.
                Application.DoEvents();
            }
        }
        #endregion
    }
}
